#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/socket.h>
#include "sip.h"
#include "dictionary.h"
#include "xmppconnect.h"
static pthread_t sipxmpp_sip_reading_thread;
static int sipxmpp_sip_server_fd;
static int stopping;
int sip_listen_port;
#define NONCE_LEN 10
#define SIP_BUFFER_SIZE 2048

#define sip_uri_t struct sip_uri
struct sip_uri
{
	char *username;
	short username_len;
	char *domain;
	short domain_len;

	char *tag;
	short tag_len;
};
struct sip_header
{
	char occupied;
	char  *name;
	int name_len;
	char *value;
	int value_len;
	struct sip_header *next;
	struct sip_header *nextinmemory;
};
static struct sip_header *sip_headers;
static pthread_mutex_t sip_headers_mutex;
#define sip_package_t struct sip_package
struct sip_package
{
	char occupied;
	char *first_line;
	int first_line_len;
	struct sip_header *headers;
	char *method;
	int method_len;
	char *from;
	int from_len;
	char *to;
	int to_len;
	char *to_tag;
	int to_tag_len;
	char *contact;
	char contact_len;
	char *call_id;
	int call_id_len;
	sip_package_t *nextinmemory;
};
static sip_package_t *sip_packages;
static pthread_mutex_t sip_packages_mutex;

#define sip_nonce_t struct sip_nonce
struct sip_nonce
{
	char occupied;
	time_t allocated_time;
	char nonce[NONCE_LEN *2 + 1];
	char callid[255];
	sip_nonce_t *next;
};
static sip_nonce_t *sip_nonces;
static pthread_mutex_t sip_nonce_mutex;
static sip_nonce_t *xmpp_get_avaiable_sip_nonce();
static int xmpp_verify_sip_nonce(char *nonce);

#define sip_dialog_t struct sip_dialog
struct sip_dialog
{
	char occupied;
	char call_id[255];
	char from_tag[255];
	char from[255];
	char via[255];
	char to[255];
	char cseq[50];
	char contact[255];
	char mycontact[255];
	char accepted;
	char incoming;
	int sequence;
	struct _sip_user_ *sip_user;
	struct ice_rtp_connection *rtp;
	xmpp_session_t *xmpp_session;
	sip_dialog_t *next;
};

char sip_user_agent[50];

extern int errno;
static char *sip_sendbuffer;
static char *sip_bodybuffer;
#define fill_with_request_default(__buffer__,__buffer_len__,__package__,__content_length__)  fill_with_request(__buffer__,__buffer_len__,__package__,__content_length__,5,"Via","From","To","Call-ID","CSeq")
static char *fill_with_request(char *buffer,int buffer_size,sip_package_t *package,int content_length,int parameters_count,...);
#define sipxmpp_find_sip_dialog(_callerid,_from,_sip_dialog) sipxmpp_find_sip_dialog_with_len(_callerid,strlen(_callerid),_from,strlen(_from),_sip_dialog)
static int sipxmpp_find_sip_dialog_with_len(char *callerid,int callerid_len,char *from,int from_len,sip_dialog_t **sip_dialog);
static int sipxmpp_find_sip_dialog_by_request(sip_package_t *package,sip_dialog_t **sip_dialog);
static int sipxmpp_create_sip_dialog_by_request(sip_package_t *package, char *buffer, char *body, int buffer_count,sip_dialog_t **sip_dialog);
static sip_dialog_t *xmpp_get_avaiable_sipxmpp_dialog();
static void xmpp_release_sip_dialog(sip_dialog_t *sip_dialog);

static void *sipxmpp_sip_reading(void * obj);
static struct sip_header *sipxmpp_sip_find_header(struct sip_package *package,char *headername);
static int sipxmpp_create_via(struct sockaddr_in remote_addr,char *via);
static size_t sipxmpp_sendto(int socket, const void *message, size_t length,int flags, const struct sockaddr *dest_addr,socklen_t dest_len);
static int sip_guess_my_ip_addr(struct sockaddr_in remote_addr,struct sockaddr_in *my_addr);
static int sip_decode_sip_uri(char *data,int len,sip_uri_t *uri);
static int sipxmpp_sip_decode(char *data,int data_len,struct sip_package **package,char **body);
static int sip_authricate(struct sip_package *package,struct _sip_user_ **sip_user,char *nonce,int nonce_size);
static int xmpp_session_status_changed_callback(struct xmpp_connection *connection,xmpp_session_t *session,enum SIPXMPP_SESSION_STATUS status);


static int sequence;

static struct sip_header *xmpp_get_avaiable_sip_header();
static void xmpp_release_sip_header(struct sip_header *sip_header);
static sip_package_t *xmpp_get_avaiable_sip_package();
static void xmpp_release_sip_package(sip_package_t *sip_package);


static sip_nonce_t *xmpp_get_avaiable_sip_nonce()
{
	time_t now;
	time(&now);
	pthread_mutex_lock(&sip_nonce_mutex);
	sip_nonce_t *sip_nonce = sip_nonces;
	while(sip_nonce)
	{
		if(!sip_nonce->occupied || now - sip_nonce->allocated_time > 60)
		{
			goto finish;
		}
		sip_nonce = sip_nonce->next;
	}

	sip_nonce = sipxmpp_calloc(sizeof(sip_nonce_t));
	if(!sip_nonces)
	{
		sip_nonces = sip_nonce;
	}
	else
	{
		sip_nonce_t *tmp_sip_nonce = sip_nonces;
		while(tmp_sip_nonce->next)
		{
			tmp_sip_nonce = tmp_sip_nonce->next;
		}
		tmp_sip_nonce->next = sip_nonce;
	}
	finish:
	sip_nonce->occupied = 1;
	pthread_mutex_unlock(&sip_nonce_mutex);
	return sip_nonce;

}
static void __xmpp_release_sip_nonce__(sip_nonce_t *sip_nonce)
{
	pthread_mutex_lock(&sip_nonce_mutex);
	sip_nonce_t *tmp_sip_nonce;
	tmp_sip_nonce = sip_nonces;

	while(tmp_sip_nonce)
	{
		if(tmp_sip_nonce == sip_nonce)
		{
			memset(tmp_sip_nonce,0,sizeof(sip_nonce_t) - sizeof(sip_nonce_t *));
			break;
		}
		tmp_sip_nonce = tmp_sip_nonce->next;
	}
	pthread_mutex_unlock(&sip_nonce_mutex);
}

static int xmpp_verify_sip_nonce(char *nonce)
{
	time_t now;
	time(&now);
	pthread_mutex_lock(&sip_nonce_mutex);
	sip_nonce_t *tmp_sip_nonce;
	tmp_sip_nonce = sip_nonces;
	while(tmp_sip_nonce)
	{
		if(tmp_sip_nonce->occupied && now - tmp_sip_nonce->allocated_time < 60 && !strcmp(nonce,tmp_sip_nonce->nonce))
		{
			__xmpp_release_sip_nonce__(tmp_sip_nonce);
			return S_OK;
		}
		tmp_sip_nonce = tmp_sip_nonce->next;
	}
	pthread_mutex_unlock(&sip_nonce_mutex);
	return S_ERROR;
}


static sip_dialog_t *sip_dialogs;
static pthread_mutex_t sipxmpp_sip_dialogs_mutex;
static sip_dialog_t *xmpp_get_avaiable_sipxmpp_dialog()
{
	pthread_mutex_lock(&sipxmpp_sip_dialogs_mutex);
	sip_dialog_t *sip_dialog = sip_dialogs;
	while(sip_dialog)
	{
		if(!sip_dialog->occupied)
		{
			goto finish;
		}
		sip_dialog = sip_dialog->next;
	}

	sip_dialog = sipxmpp_calloc(sizeof(sip_dialog_t));
	if(!sip_dialogs)
	{
		sip_dialogs = sip_dialog;
	}
	else
	{
		sip_dialog_t *tmp_sip_dialog = sip_dialogs;
		while(tmp_sip_dialog->next)
		{
			tmp_sip_dialog = tmp_sip_dialog->next;
		}
		tmp_sip_dialog->next = sip_dialog;
	}
	finish:
	sip_dialog->occupied = 1;
	pthread_mutex_unlock(&sipxmpp_sip_dialogs_mutex);
	return sip_dialog;

}
static void xmpp_release_sip_dialog(sip_dialog_t *sip_dialog)
{
	pthread_mutex_lock(&sipxmpp_sip_dialogs_mutex);
	sip_dialog_t *tmp_sip_dialog;
	tmp_sip_dialog = sip_dialogs;
	while(tmp_sip_dialog)
	{
		if(tmp_sip_dialog == sip_dialog)
		{
			destroy_rtp_connection(sip_dialog->rtp);
			memset(tmp_sip_dialog,0,sizeof(sip_dialog_t) - sizeof(sip_dialog_t *));
			break;
		}
		tmp_sip_dialog = tmp_sip_dialog->next;
	}
	pthread_mutex_unlock(&sipxmpp_sip_dialogs_mutex);
}


static struct sip_header *xmpp_get_avaiable_sip_header()
{
	pthread_mutex_lock(&sip_headers_mutex);
	struct sip_header *sip_header = sip_headers;
	while(sip_header)
	{
		if(!sip_header->occupied)
		{
			goto finish;
		}
		sip_header = sip_header->nextinmemory;
	}

	sip_header = sipxmpp_calloc(sizeof(struct sip_header));
	if(!sip_headers)
	{
		sip_headers = sip_header;
	}
	else
	{
		struct sip_header *tmp_sip_header = sip_headers;
		while(tmp_sip_header->nextinmemory)
		{
			tmp_sip_header = tmp_sip_header->nextinmemory;
		}
		tmp_sip_header->nextinmemory = sip_header;
	}
	finish:
	sip_header->occupied = 1;
	pthread_mutex_unlock(&sip_headers_mutex);
	return sip_header;

}
static void xmpp_release_sip_header(struct sip_header *sip_header)
{
	pthread_mutex_lock(&sip_headers_mutex);
	struct sip_header *tmp_header;
	tmp_header = sip_headers;
	while(tmp_header)
	{
		if(tmp_header == sip_header)
		{
			memset(tmp_header,0,sizeof(struct sip_header) - sizeof(struct sip_header *));
			break;
		}
		tmp_header = tmp_header->nextinmemory;
	}
	pthread_mutex_unlock(&sip_headers_mutex);
}
static sip_package_t *xmpp_get_avaiable_sip_package()
{
	pthread_mutex_lock(&sip_packages_mutex);
	sip_package_t *sip_package = sip_packages;
	while(sip_package)
	{
		if(!sip_package->occupied)
		{
			goto finish;
		}
		sip_package = sip_package->nextinmemory;
	}

	sip_package = sipxmpp_calloc(sizeof(sip_package_t));
	if(!sip_packages)
	{
		sip_packages = sip_package;
	}
	else
	{
		sip_package_t *tmp_sip_package = sip_packages;
		while(tmp_sip_package->nextinmemory)
		{
			tmp_sip_package = tmp_sip_package->nextinmemory;
		}
		tmp_sip_package->nextinmemory = sip_package;
	}
	finish:
	sip_package->occupied = 1;
	pthread_mutex_unlock(&sip_packages_mutex);
	return sip_package;

}
static void xmpp_release_sip_package(sip_package_t *sip_package)
{
	sip_package_t *tmp_package;


	//release it's headers
	struct sip_header *header_next;
	while(sip_package->headers)
	{
		header_next = sip_package->headers->next;
		xmpp_release_sip_header(sip_package->headers);
		sip_package->headers = header_next;
	}

	pthread_mutex_lock(&sip_packages_mutex);
	tmp_package = sip_packages;
	while(tmp_package)
	{
		if(tmp_package == sip_package)
		{
			memset(tmp_package,0,sizeof(sip_package_t) - sizeof(sip_package_t *));
			break;
		}
		tmp_package = tmp_package->nextinmemory;
	}
	pthread_mutex_unlock(&sip_packages_mutex);
}


static int sipxmpp_find_sip_dialog_with_len(char *callerid,int callerid_len,char *from,int from_len,sip_dialog_t **sip_dialog)
{
	*sip_dialog = sip_dialogs;
	while(*sip_dialog)
	{
		if((*sip_dialog)->occupied && !xmpp_cmpstr(callerid,(*sip_dialog)->call_id,callerid_len))//&& !xmpp_cmpstr(from,(*sip_dialog)->from,from_len))
		{
			return S_OK;
		}
		(*sip_dialog) = (*sip_dialog)->next;
	}
	return S_ERROR;
}
static int sipxmpp_find_sip_dialog_by_request(sip_package_t *package,sip_dialog_t **sip_dialog)
{
	struct sip_header *callid_header,*from_header;
	callid_header = sipxmpp_sip_find_header(package,"Call-ID");
	from_header = sipxmpp_sip_find_header(package,"From");
	if(callid_header && from_header)
		return sipxmpp_find_sip_dialog_with_len(callid_header->value,callid_header->value_len,from_header->value,from_header->value_len,sip_dialog);
	else
		return S_ERROR;

}

static int sipxmpp_create_sip_dialog_by_request(sip_package_t *package, char *buffer, char *body, int buffer_count,sip_dialog_t **sip_dialog)
{

	char *lineend;
	char *line;
	int line_len;
	char done = 0;
	char ip[25];
	char port[10];
	int retcode = 0;
	char rtpmapname[40];
	int rtpmapid;

	struct sip_header *tmp_header;
	sip_uri_t to_uri;
	*sip_dialog = NULL;
	if(!sipxmpp_find_sip_dialog_by_request(package,sip_dialog))//dialog already exist. return
	{
		LogE("dialog already exists.");
		gotofinish(S_ERROR);
	}

	*sip_dialog = xmpp_get_avaiable_sipxmpp_dialog();
	(*sip_dialog)->rtp = create_new_rtp_connection(NULL);
	while(1)
	{
		lineend = strchr(body,'\n');
		line = body;
		if(!lineend || lineend >= buffer + buffer_count)
		{
			line_len = buffer + buffer_count - body;
			done = 1;
			break;
		}
		else
		{
			line_len = lineend - body - 1;
			body = lineend+1;
		}
		#define C_IN_IP4 "c=IN IP4 "
		if(strstr(line,C_IN_IP4) == line)
		{
			sscanf(line,"%*s %*s %s",ip);
		}
		#define M_AUDIO "m=audio "
		if(strstr(line,M_AUDIO) == line)
		{
			sscanf(line,"%*s %s",port);
		}
		if(strstr(line,"a=rtpmap:") == line)
		{
			memset(rtpmapname,0,40);
			if(sscanf(line,"a=rtpmap:%d %4c",&rtpmapid,rtpmapname) >= 2 && !strncmp(rtpmapname,"PCMU",40)) (*sip_dialog)->rtp->payload_type_pcmu = rtpmapid;
			memset(rtpmapname,0,40);
			if(sscanf(line,"a=rtpmap:%d %15c",&rtpmapid,rtpmapname) >= 2 && !strncmp(rtpmapname,"telephone-event",40)) (*sip_dialog)->rtp->payload_type_telephone_event = rtpmapid;
		}

		if(done)
		{
			break;
		}
	}


	if((tmp_header = sipxmpp_sip_find_header(package,"Call-ID")) != NULL) sprintf((*sip_dialog)->call_id,"%.*s",tmp_header->value_len,tmp_header->value);else {LogE("no Call-ID.");return S_ERROR;}
	if((tmp_header = sipxmpp_sip_find_header(package,"Via")) != NULL) sprintf((*sip_dialog)->via,"%.*s",tmp_header->value_len,tmp_header->value);else {LogE("no via.");return S_ERROR;}
	if((tmp_header = sipxmpp_sip_find_header(package,"From")) != NULL) sprintf((*sip_dialog)->from,"%.*s",tmp_header->value_len,tmp_header->value);else {LogE("no from.");return S_ERROR;}
	if((tmp_header = sipxmpp_sip_find_header(package,"To")) != NULL) sprintf((*sip_dialog)->to,"%.*s",tmp_header->value_len,tmp_header->value);else {LogE("no to.");return S_ERROR;}
	if((tmp_header = sipxmpp_sip_find_header(package,"CSeq")) != NULL) sprintf((*sip_dialog)->cseq,"%.*s",tmp_header->value_len,tmp_header->value);else {LogE("no cseq.");return S_ERROR;}
	if((tmp_header = sipxmpp_sip_find_header(package,"Contact")) != NULL) sprintf((*sip_dialog)->contact,"%.*s",tmp_header->value_len,tmp_header->value);else {LogE("no Contact.");return S_ERROR;}
	if((*sip_dialog)->cseq) sscanf((*sip_dialog)->cseq,"%d ",&((*sip_dialog)->sequence));
	LogD("dialog->sequence=[%d]",(*sip_dialog)->sequence);

	LogD("ip=%s,port=%s,pcmu=[%d],telephone_event=[%d]",ip,port,(*sip_dialog)->rtp->payload_type_pcmu,(*sip_dialog)->rtp->payload_type_telephone_event);
	resolv_ip(ip,atoi(port),&((*sip_dialog)->rtp->serv_addr));

	finish:
		if(retcode && *sip_dialog)
			xmpp_release_sip_dialog(*sip_dialog);
	return retcode;
}
static int xmpp_session_status_changed_callback(struct xmpp_connection *connection,xmpp_session_t *session,enum SIPXMPP_SESSION_STATUS status)
{
	struct _sip_user_ *sip_user	= NULL;
	sip_dialog_t *dialog		= NULL;
	int find_dialog_result		= 0;
	if(xmpp_2_sip_find_user_by_sip_user_name(connection->sip_username,&sip_user) || !sip_user)
	{
		LogD("can not find sip_user");
		return S_ERROR;
	}
	find_dialog_result = sipxmpp_find_sip_dialog(session->sessionid,session->initiator,&dialog);


	if(status == SIPXMPP_SESSION_STATUS_ACCEPTED && !find_dialog_result && dialog)
	{
		int localport;
		ice_rtp_get_local_port(dialog->rtp,&localport);
		struct sockaddr_in my_ip_addr;
		char my_ip[20];
		time_t now;
		time(&now);
		sip_guess_my_ip_addr(sip_user->client_addr,&my_ip_addr);
		inet_ntop(AF_INET,&my_ip_addr.sin_addr,my_ip,sizeof(my_ip));
		dialog->accepted = 1;
		snprintf(sip_bodybuffer,SIP_BUFFER_SIZE,"v=0\r\no=- %lu %lu IN IP4 %s\r\ns=-\r\nc=IN IP4 %s\r\nt=0 0\r\nm=audio %d RTP/AVP 0 101\r\na=rtpmap:0 PCMU/8000\r\na=rtpmap:101 telephone-event/8000\r\na=ptime:20\r\n",now,now,my_ip,my_ip,localport);
		snprintf(sip_sendbuffer,SIP_BUFFER_SIZE,"SIP/2.0 200 OK\r\nVia: %s\r\nFrom: %s\r\nTo: %s\r\nCall-ID: %s\r\nCSeq: %s\r\nServer: %s\r\nContact: %s\r\nAllow: INVITE, CANCEL, BYE, ACK, NOTIFY\r\nContent-Type: application/sdp\r\nContent-Length: %u\r\n\r\n%s"
			,dialog->via,dialog->from,dialog->to,dialog->call_id,dialog->cseq,sip_user_agent,dialog->mycontact,(int)strlen(sip_bodybuffer),sip_bodybuffer);
		sipxmpp_sendto(sipxmpp_sip_server_fd,sip_sendbuffer,strlen(sip_sendbuffer),0,(const struct sockaddr *)&sip_user->client_addr,sizeof(struct sockaddr_in));
		glue_rtp_together(dialog->rtp,session->rtp_connection);
	}
	else if(status == SIPXMPP_SESSION_STATUS_TERMINATED && !find_dialog_result && dialog)
	{
		if(dialog->incoming)
		{
			snprintf(sip_sendbuffer,SIP_BUFFER_SIZE,"%s %s;transport=UDP SIP/2.0\r\nVia: %s\r\nFrom: %s\r\nTo: %s\r\nCall-ID: %s\r\nCSeq: %u %s\r\nUser-Agent: %s\r\nMax-Forwards: 70\r\nContact: %s\r\nAllow: INVITE, CANCEL, BYE, ACK, NOTIFY\r\nContent-Length: 0\r\n\r\n"
				, dialog->accepted ? "BYE":"CANCEL" ,sip_user->register_contact,dialog->via,dialog->from,dialog->to,dialog->call_id,dialog->accepted ? ++sequence:dialog->sequence,dialog->accepted ? "BYE":"CANCEL",sip_user_agent,dialog->mycontact);
			if(dialog->accepted)
			{
				xmpp_release_sip_dialog(dialog);
			}
		}
		else
		{
			if(dialog->accepted)
			{
				char bye_via[255];//,invite_serial[30];
				memset(bye_via,0,255);
				sipxmpp_create_via(sip_user->client_addr,bye_via);
				snprintf(sip_sendbuffer,SIP_BUFFER_SIZE,"%s %s SIP/2.0\r\nVia: %s\r\nFrom: %s\r\nTo: %s\r\nCall-ID: %s\r\nCSeq: %u %s\r\nUser-Agent: %s\r\nMax-Forwards: 70\r\nContact: %s\r\nAllow: INVITE, CANCEL, BYE, ACK, NOTIFY\r\nContent-Length: 0\r\n\r\n"
					, "BYE",sip_user->register_contact,bye_via,dialog->to,dialog->from,dialog->call_id,dialog->accepted ? ++sequence:dialog->sequence,"BYE",sip_user_agent,dialog->mycontact);
				xmpp_release_sip_dialog(dialog);
			}
			else
			{
				snprintf(sip_sendbuffer,SIP_BUFFER_SIZE,"SIP/2.0 487 Request Terminated\r\nVia: %s\r\nFrom: %s\r\nTo: %s\r\nCall-ID: %s\r\nCSeq: %d INVITE\r\nServer: %s\r\nAllow: INVITE, CANCEL, BYE, ACK, NOTIFY\r\nContent-Length: 0\r\n\r\n"
					,dialog->via
					,dialog->from
					,dialog->to
					,dialog->call_id
					,dialog->sequence
					,sip_user_agent
					);
			}
		}
		sipxmpp_sendto(sipxmpp_sip_server_fd,sip_sendbuffer,strlen(sip_sendbuffer),0,(const struct sockaddr *)&sip_user->client_addr,sizeof(struct sockaddr_in));
	}
	else if(status == SIPXMPP_SESSION_STATUS_REQUEST && find_dialog_result)
	{
		int localport;
		char from_tag_rand[6];
		char my_ip[20];
		struct sockaddr_in my_ip_addr;
		LogD("REMOTE CALLING");
		dialog = xmpp_get_avaiable_sipxmpp_dialog();
		dialog->xmpp_session = session;
		dialog->incoming = 1;
		dialog->accepted = 0;
		dialog->sip_user = sip_user;

		strcpy(dialog->call_id,session->sessionid);
		sipxmpp_create_via(sip_user->client_addr,dialog->via);
		//modify the from. so it's not like xxxx@voice.google.com/xxxx
		char *initiator_at = strchr(session->initiator,'@');
		int initiator_len = initiator_at ? initiator_at - session->initiator : strlen(session->initiator);

		sip_guess_my_ip_addr(sip_user->client_addr,&my_ip_addr);
		inet_ntop(AF_INET,&my_ip_addr.sin_addr,my_ip,sizeof(my_ip));
		snprintf(dialog->mycontact,255,"<sip:%.*s@%s:%d>",initiator_len,session->initiator,my_ip,sip_listen_port);

		sipxmpp_createrandomdata(from_tag_rand,sizeof(from_tag_rand));
		string2hex(from_tag_rand,sizeof(from_tag_rand),dialog->from_tag);
		sprintf(dialog->from,"%s;tag=%s",dialog->mycontact,dialog->from_tag);
		sprintf(dialog->to,"<%s;transport=UDP>",sip_user->register_contact);
		dialog->sequence = ++sequence;
		snprintf(dialog->cseq,50,"%d INVITE",dialog->sequence);
		dialog->rtp = create_new_rtp_connection(&localport);

		if(session->rtp_connection)
			snprintf(sip_bodybuffer,SIP_BUFFER_SIZE,"v=0\r\no=- 664310 664310 IN IP4 %s\r\ns=-\r\nc=IN IP4 %s\r\nt=0 0\r\nm=audio %d RTP/AVP 0 101\r\na=rtpmap:0 PCMU/8000\r\na=rtpmap:101 telephone-event/8000\r\na=ptime:20\r\n",my_ip,my_ip,localport);
		else
		{
			LogE("Opps,session does not have rtp_connection.");
		}
		snprintf(sip_sendbuffer,SIP_BUFFER_SIZE,"INVITE %s;transport=UDP SIP/2.0\r\nVia: %s\r\nMax-Forwards: 70\r\nFrom: %s\r\nTo: %s\r\nCall-ID: %s\r\nCSeq: %s\r\nContact: %s\r\nUser-Agent: %s\r\nContent-Type: application/sdp\r\nAllow: INVITE, CANCEL, BYE, ACK, NOTIFY\r\nContent-Length: %d\r\n\r\n%s"
			,sip_user->register_contact,dialog->via,dialog->from,dialog->to,dialog->call_id,dialog->cseq,dialog->mycontact,sip_user_agent,(int)strlen(sip_bodybuffer),sip_bodybuffer);

		sipxmpp_sendto(sipxmpp_sip_server_fd,sip_sendbuffer,strlen(sip_sendbuffer),0,(const struct sockaddr *)&sip_user->client_addr,sizeof(struct sockaddr_in));

	}
	else
	{
		LogD("Oops.............");
	}
	return S_ERROR;
}
static char *fill_with_request(char *buffer,int buffer_size,sip_package_t *package,int content_length,int parameters_count,...)
{
	struct sip_header *tmp_header = NULL;
	int i;
	char *result = buffer;
	va_list args;
	va_start (args, parameters_count);
	for(i=0 ; i< parameters_count; i++)
	{
		char *tofind = va_arg(args,char *);
		tmp_header = sipxmpp_sip_find_header(package,tofind);
		if(tmp_header)
		{
			snprintf(result,buffer_size,"%s: %.*s\r\n",tofind,tmp_header->value_len,tmp_header->value);
			buffer_size -= strlen(result);
			result += strlen(result);

		}
		else
		{
			LogE("can not find header [%s]",tofind);
		}
	}
	va_end (args);
	snprintf(result,buffer_size,"Server: %s\r\nAllow: INVITE, CANCEL, BYE, ACK, NOTIFY\r\nSupported: replaces, timer\r\nContent_Length: %d\r\n",sip_user_agent,content_length);
	buffer_size -= strlen(result);
	result += strlen(result);
	return result;
}
static void *sipxmpp_sip_reading(void * obj)
{
	socklen_t remote_len;
	struct sockaddr_in remote_addr;
	fd_set sip_reading_set;
	struct timeval tval;
	char *buffer = sipxmpp_calloc(SIP_BUFFER_SIZE);
	char *body = NULL;
	sip_package_t *package = NULL;
	int buffer_count = 0;
	int select_result;

	while(!stopping)
	{
		FD_ZERO(&sip_reading_set);
		FD_SET(sipxmpp_sip_server_fd,&sip_reading_set);
		tval.tv_sec = 2L;
		tval.tv_usec = 0L;
		if(!(select_result = select(FD_SETSIZE, &sip_reading_set, NULL, NULL, &tval) || !FD_ISSET(sipxmpp_sip_server_fd,&sip_reading_set)))
		{
			continue;
		}
		else
		{
			//int flags = fcntl(sipxmpp_sip_server_fd, F_GETFL, 0);
			//fcntl(sipxmpp_sip_server_fd, F_SETFL, flags | O_NONBLOCK);
			//fcntl(sipxmpp_sip_server_fd, F_SETFL, flags);
			remote_len = sizeof(struct sockaddr_in);
			buffer_count = recvfrom(sipxmpp_sip_server_fd,buffer,SIP_BUFFER_SIZE,0,(struct sockaddr *)&remote_addr,&remote_len);

			if (buffer_count < 0)
			{
				if(EAGAIN != errno)
				{
					LogE("Receive error,result=%d,desc[%s]",buffer_count,strerror(errno));
					break;
				}
				continue;
			}
			Log("<-------------------------\n%.*s",(int)buffer_count,buffer);
			if(sipxmpp_sip_decode(buffer,buffer_count,&package,&body))
			{
				Log("not a good package.");
				continue;
			}
			
			if(!xmpp_cmpstr(package->method,"REGISTER",package->method_len))
			{
				int expires = 120;
				int find_dialogresult;
				char try_xmpp_login = 0;
				char keep_alive = 0;
				char response_message[50];
				struct _sip_user_ *sip_user = NULL;
				char nonce[NONCE_LEN * 2 + 1];
				xmpp_connection_t *xmpp_connection = NULL;
				int find_xmpp_connection_result = 0;

				if(sip_authricate(package,&sip_user,nonce,NONCE_LEN * 2 + 1) || !xmpp_verify_sip_nonce(nonce) || !sip_user)//verify ok.
				{
					char random[NONCE_LEN],*tmp_response;
					sip_nonce_t *sip_nonce = xmpp_get_avaiable_sip_nonce();
					sipxmpp_createrandomdata(random,NONCE_LEN);
					string2hex(random,NONCE_LEN,sip_nonce->nonce);
					snprintf(sip_sendbuffer,SIP_BUFFER_SIZE,"SIP/2.0 401 Unauthorized\r\n");
					tmp_response = fill_with_request_default(sip_sendbuffer + strlen(sip_sendbuffer),SIP_BUFFER_SIZE - strlen(sip_sendbuffer),package,0);
					snprintf(tmp_response,SIP_BUFFER_SIZE - strlen(sip_sendbuffer),"WWW-Authenticate: Digest algorithm=MD5, realm=\"%s\", nonce=\"%s\"\r\n\r\n"
							,sip_user_agent
							,sip_nonce->nonce
					);
					sipxmpp_sendto(sipxmpp_sip_server_fd,sip_sendbuffer,strlen(sip_sendbuffer),0,(const struct sockaddr *)&remote_addr,remote_len);
					goto freepackagecontinue;
				}
				strcpy(response_message,"200 OK");
				memcpy(&sip_user->client_addr,&remote_addr,sizeof(struct sockaddr_in));
				find_xmpp_connection_result = sipxmpp_find_connection_by_sip_username(sip_user->sip_username,&xmpp_connection);
				if(!find_xmpp_connection_result && xmpp_connection->status == SIPXMPP_CONNECTION_STATUS_TRYING)
				{
					try_xmpp_login = 0;
					keep_alive = 0;
					expires = 10;
					strcpy(response_message,"200 TRYING");
				}
				else if(!find_xmpp_connection_result && xmpp_connection->status == SIPXMPP_CONNECTION_STATUS_DISCONNECTED)
				{
					try_xmpp_login = 1;
					keep_alive = 0;
					expires = 120;
					strcpy(response_message,"200 RETRYING");
				}
				else if(!find_xmpp_connection_result && xmpp_connection->status == SIPXMPP_CONNECTION_STATUS_LOGINED)
				{
					try_xmpp_login = 0;
					keep_alive = 1;
					expires = 120;
					strcpy(response_message,"200 Logined");
				}
				else if(!find_xmpp_connection_result && xmpp_connection->status == SIPXMPP_CONNECTION_STATUS_ERROR)
				{
					try_xmpp_login = 0;
					keep_alive = 0;
					expires = 180;
					strcpy(response_message,"400 Bad Request");
				}
				else if(find_xmpp_connection_result)
				{
					sipxmpp_create_xmpp_connection("talk.google.com",5222,sip_user->xmpp_username,sip_user->xmpp_password,sip_user->sip_username,&xmpp_connection);
					xmpp_connection->session_status_change = &xmpp_session_status_changed_callback;
					try_xmpp_login = 1;
					keep_alive = 0;
					expires = 60;
					strcpy(response_message,"200 CreatingXMPP");
				}
				
				snprintf(sip_user->register_contact,255,"%.*s",package->contact_len,package->contact);

				snprintf(sip_sendbuffer,SIP_BUFFER_SIZE,"SIP/2.0 %s\r\n",response_message);
				char *tmp_response = fill_with_request_default(sip_sendbuffer + strlen(sip_sendbuffer),SIP_BUFFER_SIZE - strlen(sip_sendbuffer),package,0);
				snprintf(tmp_response,SIP_BUFFER_SIZE - strlen(sip_sendbuffer),"Contact: %s;expires=%d\r\nExpires: %d\r\n\r\n"
						,sip_user->register_contact
						,expires,expires
				);
				
				sipxmpp_sendto(sipxmpp_sip_server_fd,sip_sendbuffer,strlen(sip_sendbuffer),0,(const struct sockaddr *)&remote_addr,remote_len);
				
				if(try_xmpp_login)
				{
					start_sipxmpp_login(xmpp_connection);
				}
				if(keep_alive)
				{
					sipxmpp_ping(xmpp_connection);
				}
			}
			else if(!xmpp_cmpstr(package->method,"INVITE",package->method_len))
			{
				int find_dialogresult;
				struct _sip_user_ *sip_user = NULL;
				char nonce[NONCE_LEN * 2 + 1];
				sip_dialog_t *sip_dialog = NULL;
				char tocall[240];
				char random_to_tag[6];
				sip_uri_t to_uri,from_uri;
				xmpp_connection_t *xmpp_connection = NULL;
				int find_xmpp_connection_result = 0;
				char my_ip[20];
				struct sockaddr_in my_ip_addr;
				if(sip_authricate(package,&sip_user,nonce,NONCE_LEN * 2 + 1) || !xmpp_verify_sip_nonce(nonce))//verify ok.
				{
					char random[NONCE_LEN];
					sip_nonce_t *sip_nonce = xmpp_get_avaiable_sip_nonce();
					sipxmpp_createrandomdata(random,NONCE_LEN);
					string2hex(random,NONCE_LEN,sip_nonce->nonce);
					snprintf(sip_sendbuffer,SIP_BUFFER_SIZE,"SIP/2.0 401 Unauthorized\r\n");
					char *tmp_response = fill_with_request_default(sip_sendbuffer + strlen(sip_sendbuffer),SIP_BUFFER_SIZE - strlen(sip_sendbuffer),package,0);
					snprintf(tmp_response,SIP_BUFFER_SIZE - strlen(sip_sendbuffer),"WWW-Authenticate: Digest algorithm=MD5, realm=\"%s\", nonce=\"%s\"\r\n\r\n"
							,sip_user_agent
							,sip_nonce->nonce
					);
					sipxmpp_sendto(sipxmpp_sip_server_fd,sip_sendbuffer,strlen(sip_sendbuffer),0,(const struct sockaddr *)&remote_addr,remote_len);
					goto freepackagecontinue;
				}
				find_xmpp_connection_result = sipxmpp_find_connection_by_sip_username(sip_user->sip_username,&xmpp_connection);
				if(find_xmpp_connection_result)
				{
					snprintf(sip_sendbuffer,SIP_BUFFER_SIZE,"SIP/2.0 401 Unauthorized\r\n");
					char *tmp_response = fill_with_request_default(sip_sendbuffer + strlen(sip_sendbuffer),SIP_BUFFER_SIZE - strlen(sip_sendbuffer),package,0);
					sipxmpp_sendto(sipxmpp_sip_server_fd,sip_sendbuffer,strlen(sip_sendbuffer),0,(const struct sockaddr *)&remote_addr,remote_len);
					goto freepackagecontinue;
				}
				sip_guess_my_ip_addr(remote_addr,&my_ip_addr);
				inet_ntop(AF_INET,&my_ip_addr.sin_addr,my_ip,sizeof(my_ip));

				if(sipxmpp_create_sip_dialog_by_request(package,buffer,body,buffer_count,&sip_dialog))
				{
					snprintf(sip_sendbuffer,SIP_BUFFER_SIZE,"SIP/2.0 483 CALL EXIST\r\n");
					char *tmp_response = fill_with_request_default(sip_sendbuffer + strlen(sip_sendbuffer),SIP_BUFFER_SIZE - strlen(sip_sendbuffer),package,0);
					snprintf(tmp_response,SIP_BUFFER_SIZE - strlen(sip_sendbuffer),"\r\n");
					sipxmpp_sendto(sipxmpp_sip_server_fd,sip_sendbuffer,strlen(sip_sendbuffer),0,(const struct sockaddr *)&remote_addr,remote_len);
					//error
					goto freepackagecontinue;
				}
				sip_dialog->incoming = 0;
				sip_dialog->accepted = 0;
				sip_dialog->sip_user = sip_user;
				if(sip_decode_sip_uri(sip_dialog->to,strlen(sip_dialog->to),&to_uri) || sip_decode_sip_uri(sip_dialog->from,strlen(sip_dialog->from),&from_uri))
				{
					LogE("decode 'to' header error.");
					snprintf(sip_sendbuffer,SIP_BUFFER_SIZE,"SIP/2.0 404 XMPP Error\r\nVia: %s\r\nFrom: %s\r\nTo: %s\r\nCall-ID: %s\r\nCSeq: %s\r\nServer: %s\r\nContent-Length: 0\r\n\r\n"
						,sip_dialog->via,sip_dialog->from,sip_dialog->to,sip_dialog->call_id,sip_dialog->cseq,sip_user_agent);
						sipxmpp_sendto(sipxmpp_sip_server_fd,sip_sendbuffer,strlen(sip_sendbuffer),0,(const struct sockaddr *)&remote_addr,remote_len);
					xmpp_release_sip_dialog(sip_dialog);
					goto freepackagecontinue;
				}
				snprintf(tocall,240,"%.*s@voice.google.com",to_uri.username_len,to_uri.username);
				snprintf(sip_dialog->mycontact,255,"<sip:%.*s@%s:%d>",to_uri.username_len,to_uri.username,my_ip,sip_listen_port);
				
				snprintf(sip_sendbuffer,SIP_BUFFER_SIZE,"SIP/2.0 100 Trying\r\nVia: %s\r\nFrom: %s\r\nTo: %s\r\nCall-ID: %s\r\nCSeq: %s\r\nServer: %s\r\nContact: %s\r\nAllow: INVITE, CANCEL, BYE, ACK, NOTIFY\r\nContent-Length: 0\r\n\r\n"
					,sip_dialog->via,sip_dialog->from,sip_dialog->to,sip_dialog->call_id,sip_dialog->cseq,sip_user_agent,sip_dialog->mycontact);
				sipxmpp_sendto(sipxmpp_sip_server_fd,sip_sendbuffer,strlen(sip_sendbuffer),0,(const struct sockaddr *)&remote_addr,remote_len);

				sip_dialog->xmpp_session = sipxmpp_make_call(xmpp_connection,tocall,sip_dialog->call_id);
				if(!sip_dialog->xmpp_session)
				{
					//REJECT.
					snprintf(sip_sendbuffer,SIP_BUFFER_SIZE,"SIP/2.0 404 XMPP Error\r\nVia: %s\r\nFrom: %s\r\nTo: %s\r\nCall-ID: %s\r\nCSeq: %s\r\nServer: %s\r\nContact: %s\r\nContent-Length: 0\r\n\r\n"
					,sip_dialog->via,sip_dialog->from,sip_dialog->to,sip_dialog->call_id,sip_dialog->cseq,sip_user_agent,sip_dialog->mycontact);
					sipxmpp_sendto(sipxmpp_sip_server_fd,sip_sendbuffer,strlen(sip_sendbuffer),0,(const struct sockaddr *)&remote_addr,remote_len);
					xmpp_release_sip_dialog(sip_dialog);
				}
				else
				{
					//generate a to tag.
					sprintf(sip_dialog->to + strlen(sip_dialog->to),"%s",";tag=");
					sipxmpp_createrandomdata(random_to_tag,sizeof(random_to_tag));
					string2hex(random_to_tag,sizeof(random_to_tag),sip_dialog->to + strlen(sip_dialog->to));

					//Ringing 180 Ringing
					snprintf(sip_sendbuffer,SIP_BUFFER_SIZE,"SIP/2.0 180 Ringing\r\nVia: %s\r\nFrom: %s\r\nTo: %s\r\nCall-ID: %s\r\nCSeq: %s\r\nServer: %s\r\nContact: %s\r\nAllow: INVITE, CANCEL, BYE, ACK, NOTIFY\r\nContent-Length: 0\r\n\r\n"
						,sip_dialog->via,sip_dialog->from,sip_dialog->to,sip_dialog->call_id,sip_dialog->cseq,sip_user_agent,sip_dialog->mycontact);
					sipxmpp_sendto(sipxmpp_sip_server_fd,sip_sendbuffer,strlen(sip_sendbuffer),0,(const struct sockaddr *)&remote_addr,remote_len);
				}
			}
			else if(!xmpp_cmpstr(package->method,"BYE",package->method_len) || !xmpp_cmpstr(package->method,"CANCEL",package->method_len))
			{
				sip_dialog_t *sip_dialog = NULL;
				if(!sipxmpp_find_sip_dialog_by_request(package,&sip_dialog) && sip_dialog)
				{
					xmpp_connection_t *xmpp_connection = NULL;
					int find_xmpp_connection_result = 0;

					if(sip_dialog->sip_user && sip_dialog->xmpp_session
							&& !sipxmpp_find_connection_by_sip_username(sip_dialog->sip_user->sip_username,&xmpp_connection) && xmpp_connection)
					{
						if(!xmpp_cmpstr(package->method,"CANCEL",package->method_len))
						{
							snprintf(sip_sendbuffer,SIP_BUFFER_SIZE,"SIP/2.0 487 Request Terminated\r\nVia: %s\r\nFrom: %s\r\nTo: %s\r\nCall-ID: %s\r\nCSeq: %d INVITE\r\nServer: %s\r\nAllow: INVITE, CANCEL, BYE, ACK, NOTIFY\r\nContent-Length: 0\r\n\r\n"
														,sip_dialog->via
														,sip_dialog->from
														,sip_dialog->to
														,sip_dialog->call_id
														,sip_dialog->sequence
														,sip_user_agent
														);
							sipxmpp_sendto(sipxmpp_sip_server_fd,sip_sendbuffer,strlen(sip_sendbuffer),0,(const struct sockaddr *)&remote_addr,remote_len);
						}
						snprintf(sip_sendbuffer,SIP_BUFFER_SIZE,"SIP/2.0 200 OK\r\n");
						char *tmp_response = fill_with_request_default(sip_sendbuffer + strlen(sip_sendbuffer),SIP_BUFFER_SIZE - strlen(sip_sendbuffer),package,0);
						snprintf(tmp_response,SIP_BUFFER_SIZE - strlen(sip_sendbuffer),"\r\n");
						sipxmpp_sendto(sipxmpp_sip_server_fd,sip_sendbuffer,strlen(sip_sendbuffer),0,(const struct sockaddr *)&remote_addr,remote_len);

						LogD("found dialog. sending terminate.");
						if(sip_dialog->rtp)
							stop_rtp_connection(sip_dialog->rtp);
						sipxmpp_terminate_call(xmpp_connection,sip_dialog->xmpp_session,"success");
						xmpp_release_sip_dialog(sip_dialog);
					}
					else
					{
						LogD("Oops..............");
					}
				}
				else
				{
					Log("sip_dialog not exists.");
				}
			}
			else if(!xmpp_cmpstr(package->method,"NOTIFY",package->method_len))
			{
				snprintf(sip_sendbuffer,SIP_BUFFER_SIZE,"SIP/2.0 200 OK\r\n");
				char *tmp_response = fill_with_request_default(sip_sendbuffer + strlen(sip_sendbuffer),SIP_BUFFER_SIZE - strlen(sip_sendbuffer),package,0);
				snprintf(tmp_response,SIP_BUFFER_SIZE - strlen(sip_sendbuffer),"\r\n");
				sipxmpp_sendto(sipxmpp_sip_server_fd,sip_sendbuffer,strlen(sip_sendbuffer),0,(const struct sockaddr *)&remote_addr,remote_len);
			}
			else if(!xmpp_cmpstr(package->method,"OPTIONS",package->method_len))
			{	
				snprintf(sip_sendbuffer,SIP_BUFFER_SIZE,"SIP/2.0 200 OK\r\n");
				char *tmp_response = fill_with_request_default(sip_sendbuffer + strlen(sip_sendbuffer),SIP_BUFFER_SIZE - strlen(sip_sendbuffer),package,0);
				snprintf(tmp_response,SIP_BUFFER_SIZE - strlen(sip_sendbuffer),"\r\n");
				sipxmpp_sendto(sipxmpp_sip_server_fd,sip_sendbuffer,strlen(sip_sendbuffer),0,(const struct sockaddr *)&remote_addr,remote_len);

			}
			else if(!xmpp_cmpstr(package->method,"INFO",package->method_len))
			{
				snprintf(sip_sendbuffer,SIP_BUFFER_SIZE,"SIP/2.0 500 Not Supported\r\n");
				char *tmp_response = fill_with_request_default(sip_sendbuffer + strlen(sip_sendbuffer),SIP_BUFFER_SIZE - strlen(sip_sendbuffer),package,0);
				snprintf(tmp_response,SIP_BUFFER_SIZE - strlen(sip_sendbuffer),"\r\n");
				sipxmpp_sendto(sipxmpp_sip_server_fd,sip_sendbuffer,strlen(sip_sendbuffer),0,(const struct sockaddr *)&remote_addr,remote_len);
			}
			else if(!xmpp_cmpstr(package->method,"SIP/2.0",package->method_len))
			{
				sip_dialog_t *sip_dialog = NULL;
				int responsecode;
				int original_sequence;
				char original_request_command[50];
				char original_request_cseq[50];
				xmpp_connection_t *xmpp_connection = NULL;
				struct sip_header *cseq_header = sipxmpp_sip_find_header(package,"CSeq");
				sipxmpp_find_sip_dialog_by_request(package,&sip_dialog);
				if(cseq_header && snprintf(original_request_cseq,50,"%.*s",cseq_header->value_len,cseq_header->value) > 0
						&& sscanf(package->first_line,"%*s %d",&responsecode) == 1
						&& sscanf(original_request_cseq,"%d %s",&original_sequence,original_request_command) == 2)
				{
					if(!strcmp(original_request_command,"INVITE"))
					{
						if(sipxmpp_find_sip_dialog_by_request(package,&sip_dialog)
							|| sipxmpp_find_connection_by_sip_username(sip_dialog->sip_user->sip_username,&xmpp_connection) || !xmpp_connection)
						{
							LogD("can not find dialog");
							goto freepackagecontinue;
						}
						if(responsecode >= 100 && responsecode < 200)
						{
							Log("continue waitting.");
						}
						else if(responsecode >= 200 && responsecode < 300)
						{
							if(!sip_dialog->accepted)
							{
								char *lineend;
								char *line;
								int line_len;
								char done = 0;
								char sequence[50];
								struct sip_header *tmp_header;
								if((tmp_header = sipxmpp_sip_find_header(package,"To")) != NULL) snprintf(sip_dialog->to, 255,"%.*s",tmp_header->value_len,tmp_header->value);


								char ip[25];
								char port[10];
								int rtpmapid;
								char rtpmapname[40];
								while(1)
								{
									lineend = strchr(body,'\n');
									line = body;
									if(!lineend || lineend >= buffer + buffer_count)
									{
										line_len = buffer + buffer_count - body;
										done = 1;
										break;
									}
									else
									{
										line_len = lineend - body - 1;
										body = lineend+1;
									}
									#define C_IN_IP4 "c=IN IP4 "
									if(strstr(line,C_IN_IP4) == line)
									{
										sscanf(line,"%*s %*s %s",ip);
									}
									#define M_AUDIO "m=audio "
									if(strstr(line,M_AUDIO) == line)
									{
										sscanf(line,"%*s %s",port);
									}
									if(strstr(line,"a=rtpmap:") == line)
									{
										memset(rtpmapname,0,40);
										if(sscanf(line,"a=rtpmap:%d %4c",&rtpmapid,rtpmapname) >= 2 && !strncmp(rtpmapname,"PCMU",40)) sip_dialog->rtp->payload_type_pcmu = rtpmapid;
										memset(rtpmapname,0,40);
										if(sscanf(line,"a=rtpmap:%d %15c",&rtpmapid,rtpmapname) >= 2 && !strncmp(rtpmapname,"telephone-event",40)) sip_dialog->rtp->payload_type_telephone_event = rtpmapid;
									}
									if(done)
									{
										break;
									}
								}
								sprintf(sequence,"%d ACK",sip_dialog->sequence);
								snprintf(sip_sendbuffer,SIP_BUFFER_SIZE,"ACK %s;transport=UDP SIP/2.0\r\nVia: %s\r\nMax-Forwards: 70\r\nFrom: %s\r\nTo: %s\r\nCall-ID: %s\r\nCSeq: %s\r\nContact: %s\r\nUser-Agent: %s\r\nAllow: INVITE, CANCEL, BYE, ACK, NOTIFY\r\nContent-Length: 0\r\n\r\n"
									,sip_dialog->sip_user->register_contact,sip_dialog->via,sip_dialog->from,sip_dialog->to,sip_dialog->call_id,sequence,sip_dialog->mycontact,sip_user_agent);
								sipxmpp_sendto(sipxmpp_sip_server_fd,sip_sendbuffer,strlen(sip_sendbuffer),0,(const struct sockaddr *)&sip_dialog->sip_user->client_addr,sizeof(struct sockaddr_in));
								sip_xmpp_send_accept(xmpp_connection,sip_dialog->xmpp_session);
								LogD("remote call accepted.");
								sip_dialog->accepted = 1;
								LogD("ip=%s,port=%s,pcmu=[%d],telephone_event=[%d]",ip,port,sip_dialog->rtp->payload_type_pcmu,sip_dialog->rtp->payload_type_telephone_event);
								resolv_ip(ip,atoi(port),&(sip_dialog->rtp->serv_addr));
								glue_rtp_together(sip_dialog->rtp,sip_dialog->xmpp_session->rtp_connection);
							}
							else
							{
								LogE("call already accepted.");
							}
						}
						else if(responsecode >=300 && responsecode < 400)
						{
							LogE("client responsed 300-400 code. we do not support it, yet.");
							sipxmpp_terminate_call(xmpp_connection,sip_dialog->xmpp_session,"busy");
							xmpp_release_sip_dialog(sip_dialog);
						}
						else if(responsecode >=400 && responsecode < 699)
						{
							char sequence[50];
							sprintf(sequence,"%d ACK",sip_dialog->sequence);
							sprintf(sip_dialog->to + strlen(sip_dialog->to),"%.*s",package->to_tag_len,package->to_tag);
							snprintf(sip_sendbuffer,SIP_BUFFER_SIZE,"ACK %s;transport=UDP SIP/2.0\r\nVia: %s\r\nMax-Forwards: 70\r\nFrom: %s\r\nTo: %s\r\nCall-ID: %s\r\nCSeq: %s\r\nContact: %s\r\nUser-Agent: %s\r\nAllow: INVITE, CANCEL, BYE, ACK, NOTIFY\r\nContent-Length: 0\r\n\r\n"
								,sip_dialog->sip_user->register_contact,sip_dialog->via,sip_dialog->from,sip_dialog->to,sip_dialog->call_id,sequence,sip_dialog->mycontact,sip_user_agent);
							sipxmpp_sendto(sipxmpp_sip_server_fd,sip_sendbuffer,strlen(sip_sendbuffer),0,(const struct sockaddr *)&sip_dialog->sip_user->client_addr,sizeof(struct sockaddr_in));

							if(responsecode == 486)
							{
								LogI("busy here===============");
							}

							if(responsecode != 487) //xmpp send us terminate. that why we CANCEL this call. so do not terminate again.
							{
								sipxmpp_terminate_call(xmpp_connection,sip_dialog->xmpp_session,"busy");
							}
							xmpp_release_sip_dialog(sip_dialog);
						}
						else
						{
							LogE("Unknown status code.responsecode=%d",responsecode);
						}
					}
					else if(!strcmp(original_request_command,"CANCEL") || !strcmp(original_request_command,"BYE"))
					{
						LogD("got CANCEL OR BYE RESPONSE, IGNORE IT.");
					}

				}
				else
				{
					LogE("can not find dialog or does not contain a valid response number");
				}
			}
			freepackagecontinue:
			xmpp_release_sip_package(package);
		}
		
	}
	chkndfree(buffer);
	return NULL;
}

static struct sip_header *sipxmpp_sip_find_header(struct sip_package *package,char *headername)
{
	struct sip_header *header = package->headers;
	while(header)
	{
		if(!memcmp(header->name,headername,MIN(header->name_len,strlen(headername))))
		{
			return header;
		}
		header = header->next;
	}
	return NULL;
}
static int sipxmpp_create_via(struct sockaddr_in remote_addr,char *via)
{
	struct sockaddr_in my_ip_addr;
	char my_ip[20];
	char rand[4];
	sip_guess_my_ip_addr(remote_addr,&my_ip_addr);
	inet_ntop(AF_INET,&my_ip_addr.sin_addr,my_ip,sizeof(my_ip));
	sprintf(via,"SIP/2.0/UDP %s:%d;branch=",my_ip,sip_listen_port);
	sipxmpp_createrandomdata(rand,4);
	string2hex(rand,4,via + strlen(via));
	return 0;
}
static size_t sipxmpp_sendto(int socket, const void *message, size_t length,int flags, const struct sockaddr *dest_addr,socklen_t dest_len)
{
	char dst_ip_str[50];
	int nport = NTOHS(*((short*)(dest_addr->sa_data)));
	inet_ntop(dest_addr->sa_family,dest_addr->sa_data + (dest_addr->sa_family == AF_INET ? 2 : 6),dst_ip_str, sizeof(dst_ip_str));
	
	LogD("------%s:%d------------>\n%.*s",dst_ip_str,nport,(int)length,(char *)message);
	return sendto(socket,message,length,flags,dest_addr,dest_len);
}
/**
  @brief guess my ip. use ip & mask == remote ip & mask. so not support INTERNET yet.
*/
static int sip_guess_my_ip_addr(struct sockaddr_in remote_addr,struct sockaddr_in *my_addr)
{
	struct ifconf ifconf;
	struct ifreq ifr[50];
	struct ifreq netmask;
	int ifs,i;
	ifconf.ifc_buf = (char *) ifr;
	ifconf.ifc_len = sizeof ifr;
	if (ioctl(sipxmpp_sip_server_fd, SIOCGIFCONF , &ifconf) == -1) {
		return 1;
	}
	ifs = ifconf.ifc_len / sizeof(ifr[0]);
	for (i = 0; i < ifs; i++) {
		char ip[INET_ADDRSTRLEN];
		struct sockaddr_in *s_in = (struct sockaddr_in *) &ifr[i].ifr_addr;
		ioctl(sipxmpp_sip_server_fd,SIOCGIFFLAGS,(caddr_t)&ifr[i]);
		
		if(((ifr[i].ifr_flags)&IFF_UP) && !((ifr[i].ifr_flags)& IFF_LOOPBACK))
		{
			memcpy(&netmask,&ifr[i],sizeof(ifr[i]));
			ioctl(sipxmpp_sip_server_fd,SIOCGIFNETMASK,(caddr_t)&netmask);
			if((((struct sockaddr_in*)&ifr[i].ifr_addr)->sin_addr.s_addr & ((struct sockaddr_in*)&netmask.ifr_netmask)->sin_addr.s_addr) == (remote_addr.sin_addr.s_addr & ((struct sockaddr_in*)&netmask.ifr_netmask)->sin_addr.s_addr))
			{
				memcpy(my_addr,(struct sockaddr_in*)&ifr[i].ifr_addr,sizeof(struct sockaddr_in));
				return 0;
			}
		}
	}
	return 1;
}



/*-------------------------------------------------------------------------*/
/**
  @brief    Decode a sip uri.
  @param    data String to decode
  @param	the result. must be inited.
  @return   the result of decode,0 for success. 
  this decode a sip uri string to sip_uri_t , this just decode the parts we need.so if we need more in the feature, add it here.
 */
/*--------------------------------------------------------------------------*/
static int sip_decode_sip_uri(char *data,int len,sip_uri_t *uri)
{
	char *at,*colon,*semicolon,*brackets,*equal;
	memset(uri,0,sizeof(sip_uri_t));
	
	uri->username = memchr(data,'<',len);
	if(uri->username && uri->username == data + len - 1)
	{
		return 1;
	}
	if(!uri->username)
	{
		uri->username = data;
	}
	at = memchr(uri->username,'@',len - (uri->username - data));
	colon = memchr(uri->username,':',len - (uri->username - data));
	if(colon && colon == data + len -1)
	{
		return 1;
	}
	colon = colon + 1;
	if(!at || at == data + len - 1)
	{
		return 1;
	}
	if(colon && colon < at) //protocol. sip:
	{
		uri->username = colon;
		uri->username_len = at - colon;
	}
	else
	{
		uri->username_len = at - data;
	}
	uri->domain = at + 1;
	semicolon = memchr(uri->domain,';',len - (uri->domain - data));
	brackets = memchr(uri->domain,'>',len - (uri->domain - data));
	
	if(!brackets)
	{
		uri->domain_len = semicolon ? semicolon - uri->domain : len - (uri->domain - data);
		return 0;
	}
	uri->domain_len = (semicolon && semicolon < brackets ? semicolon - uri->domain : brackets - uri->domain);
	colon = memchr(uri->domain,':',uri->domain_len);
	if(colon)
	{
		uri->domain_len = colon - uri->domain;
	}
	
	while(semicolon && (semicolon = memchr(semicolon,';',len - (semicolon - data))) && semicolon < data - 1)
	{
		semicolon++;
		equal = memchr(semicolon,'=',len - (semicolon - data));
		if(!equal || memchr(semicolon,';',equal - semicolon))
		{
			continue;
		}
		equal++;
		if(!memcmp(semicolon,"tag",MIN(equal-semicolon,3)))
		{
			char *nextsemicolon = memchr(equal,';',len - (equal - data));
			uri->tag = equal;
			uri->tag_len = nextsemicolon ? nextsemicolon - equal:len -(equal - data);
		}
		
	}
	return 0;
}

static int sipxmpp_sip_decode(char *data,int data_len,struct sip_package **package,char **body)
{
	*body = data;
	int retcode = 0;
	*package = xmpp_get_avaiable_sip_package();
	
	if(!(*package)->first_line)
	{
		(*package)->first_line = data;
		char *crlf = strchr(*body,'\n');
		if(!*body)
		{
			gotofinish(1);
		}
		else
		{
			(*package)->first_line_len = crlf - *body;
			if((*package)->first_line[(*package)->first_line_len - 1] == '\r')
			{
				(*package)->first_line_len--;
			}
		}
		(*package)->method = (*package)->first_line;
		(*package)->method_len = (*body = strchr((*package)->first_line,' ')) && *body < crlf ? *body - (*package)->first_line : 0;
		*body = crlf + 1;
	}
	//read headers;
	while(*body - data < data_len)
	{
		char *nameend,*crlf;
		char includecr = 0;
		struct sip_header *header;
		crlf = strchr(*body,'\n');
		if(!crlf)//no crlf,error message
		{
			Log("message error!,data=%.*s",data_len,data);

			gotofinish(1);
		}
		if(crlf && crlf > *body && *(crlf-1) == '\r') //remove \r
		{
			includecr = 1;
			crlf --;
		}
		if(crlf == *body) // header end. return the position of body
		{
			*body = crlf + 1 + includecr;
			gotofinish(0);
		}
		nameend = strchr(*body,':');
		
		header = xmpp_get_avaiable_sip_header();
		header->name = *body;
		if(crlf && nameend && nameend < crlf)
		{
			header->name_len = nameend - *body;
			*body = nameend + 1;
			header->value = *body;
			header->value_len = crlf - *body;
			
			while(header->value[0] == ' ') // remove the beginning spaces
			{
				header->value++;
				header->value_len --;
			}
			if(!xmpp_cmpstr(header->name,"From",header->name_len))
			{
				(*package)->from = header->value;
				(*package)->from_len = header->value_len;
			}
			else if(!xmpp_cmpstr(header->name,"To",header->name_len))
			{
				(*package)->to = header->value;
				(*package)->to_len = header->value_len;
				
				(*package)->to_tag = strstr(header->value,";tag=");
				if((*package)->to_tag != NULL && (*package)->to_tag > (*package)->to + (*package)->to_len)
				{
					(*package)->to_tag = NULL;
				}
				if((*package)->to_tag)
				{
					(*package)->to_tag_len = (*package)->to_len - ((*package)->to_tag - (*package)->to);
				}
				
			}
			else if(!xmpp_cmpstr(header->name,"Call-ID",header->name_len))
			{
				(*package)->call_id = header->value;
				(*package)->call_id_len = header->value_len;
			}
			else if(!xmpp_cmpstr(header->name,"Contact",header->name_len))
			{
				(*package)->contact = header->value;
				(*package)->contact_len = header->value_len;
				int i;
				for(i = 0 ; i < (*package)->contact_len ;i++)
				{
					if((*package)->contact[i] == '<')
					{
						break;
					}
				}
				if(i < (*package)->contact_len - 1)
				{
					(*package)->contact += (i + 1);
					(*package)->contact_len -= (i + 1);
				}
				for(i = 0 ; i < (*package)->contact_len ;i++)
				{
					if((*package)->contact[i] == ';')
					{
						break;
					}
				}
				if(i < (*package)->contact_len)
				{
					(*package)->contact_len = i;
				}
				for(i = 0 ; i < (*package)->contact_len ;i++)
				{
					if((*package)->contact[i] == '>')
					{
						break;
					}
				}
				if(i < (*package)->contact_len)
				{
					(*package)->contact_len = i;
				}
			}
			*body = crlf + 1 + includecr;//move to next line
		}
		else
		{
			LogE("error. header error,stop at[%s]",*body);
			xmpp_release_sip_header(header);

			gotofinish(1)
		}
		
		if((*package)->headers)
		{
			struct sip_header *tmp_header = (*package)->headers;
			while(tmp_header->next)
			{
				tmp_header = tmp_header->next;
			}
			tmp_header->next = header;
		}
		else
		{
			(*package)->headers = header;
		}
	}
	finish:
		if(retcode)
			xmpp_release_sip_package(*package);
	return retcode;
}
static void __sip_authricate_name_value_ready__(char *name,int name_len,char *value,int value_len,char *realm,char *uri,char *response, char *username,char *nonce,int nonce_size)
{
	if(!xmpp_cmpstr(name,"realm",name_len)){
		snprintf(realm,255,"%.*s",value_len,value);
		LogD("realm=[%s]",realm);
	}
	else if(!xmpp_cmpstr(name,"uri",name_len)){
		snprintf(uri,255,"%.*s",value_len,value);
		LogD("uri=[%s]",uri);
	}
	else if(!xmpp_cmpstr(name,"response",name_len)){
		snprintf(response,33,"%.*s",value_len,value);
		LogD("response=[%s]",response);
	}
	else if(!xmpp_cmpstr(name,"username",name_len)){
		snprintf(username,255,"%.*s",value_len,value);
		LogD("username=[%s]",username);
	}
	else if(!xmpp_cmpstr(name,"nonce",name_len)){
		snprintf(nonce,nonce_size,"%.*s",value_len,value);
		LogD("nonce=[%s]",nonce);
	}
}
static int sip_authricate(struct sip_package *package,struct _sip_user_ **sip_user,char *nonce,int nonce_size)
{
	struct sip_header *authorization = sipxmpp_sip_find_header(package,"Authorization");
	int i;

	if(authorization)
	{
		MD5_CTX context;
		char *name,*value;

		int name_len;
		int digest_len = 0;//if find digest method
		int i;
		int locating_value = 0;
		char realm[255],uri[255],response[33],username[255];

		char md[16];
		char h1[33],h2[33],authorization_response[33];

		memset(realm,0,255);memset(uri,0,255);memset(response,0,33);memset(username,0,255);memset(nonce,0,nonce_size);
		for(i = 0 ; i < authorization->value_len;i++)
		{
			if(!digest_len)
			{
				if(authorization->value[i] == ' ')
				{
					digest_len = i;
					name = authorization->value + i + 1;
				}
			}
			else if(!locating_value && authorization->value[i] == '=')
			{
				name_len=i-(name-authorization->value);
				value = authorization->value + i + 1;
				if(value[0] == '\"')
				{
					value++;
					i++;
				}
				locating_value = 1;
			}
			else if(authorization->value[i] == '\"' || i == authorization->value_len-1)
			{
				locating_value = 0;
				__sip_authricate_name_value_ready__(name,name_len,value,i - (int)(value - authorization->value) +(i == authorization->value_len-1? 1:0)
						,realm,uri,response, username,nonce,nonce_size);
			}
			else if(authorization->value[i] == ',')
			{
				if(locating_value)
				{
					locating_value = 0;
					__sip_authricate_name_value_ready__(name,name_len,value,i - (int)(value - authorization->value) +(i == authorization->value_len-1? 1:0)
											,realm,uri,response, username,nonce,nonce_size);
				}
				name = authorization->value + i + 1;
				while(name[0] == ' ' && name < authorization->value + authorization->value_len)
				{
					name++;
				}
			}
		}

		if(!xmpp_2_sip_find_user_by_sip_user_name(username,sip_user))
		{
			LogD("found user.");
			MD5_Init(&context);
			MD5_Update(&context, username,strlen(username));
			MD5_Update(&context, ":",1);
			MD5_Update(&context, realm,strlen(realm));
			MD5_Update(&context, ":",1);
			MD5_Update(&context, (*sip_user)->sip_password,strlen((*sip_user)->sip_password));
			MD5_Final(md, &context);
			string2hex(md,16,h1);
			MD5_Init(&context);
			MD5_Update(&context, package->method,package->method_len);
			MD5_Update(&context, ":",1);
			MD5_Update(&context, uri,strlen(uri));
			MD5_Final(md, &context);
			string2hex(md,16,h2);
			MD5_Init(&context);
			MD5_Update(&context, h1,32);
			MD5_Update(&context, ":",1);
			MD5_Update(&context, nonce,strlen(nonce));
			MD5_Update(&context, ":",1);
			MD5_Update(&context, h2,32);
			MD5_Final(md, &context);
			memset(authorization_response,0,33);
			string2hex(md,16,authorization_response);
			LogD("computed response=[%s]",authorization_response);
			if(!memcmp(response,authorization_response,32))
			{
				LogD("response is ok.");
				return S_OK;
			}
			else
			{
				LogD("response is not same.");
			}

		}
	}

	return S_ERROR;
}


int init_sip_server()
{
	struct sockaddr_in server_addr;
	int server_addr_len;	
	stopping = 0;
	sip_headers = NULL;
	sip_packages = NULL;
	sip_dialogs = NULL;
	sip_nonces = NULL;
	sipxmpp_sip_reading_thread = 0;
	sipxmpp_sip_server_fd = 0;
	//init nonce

	sip_sendbuffer = sipxmpp_calloc(SIP_BUFFER_SIZE);
	sip_bodybuffer = sipxmpp_calloc(SIP_BUFFER_SIZE);
	pthread_mutex_init(&sip_headers_mutex,NULL);
	pthread_mutex_init(&sip_packages_mutex,NULL);
	pthread_mutex_init(&sipxmpp_sip_dialogs_mutex,NULL);
	pthread_mutex_init(&sip_nonce_mutex,NULL);
	sipxmpp_sip_server_fd=socket(AF_INET, SOCK_DGRAM, 0);
	int flags = fcntl(sipxmpp_sip_server_fd, F_GETFL, 0);
	fcntl(sipxmpp_sip_server_fd, F_SETFL, flags | O_NONBLOCK);
	//fcntl(sipxmpp_sip_server_fd, F_SETFL, flags);
	if (sipxmpp_sip_server_fd < 0)
	{
		return 1;
	}
	server_addr_len = sizeof(server_addr);
	bzero(&server_addr,server_addr_len);
	server_addr.sin_family=AF_INET;
	server_addr.sin_addr.s_addr=INADDR_ANY;
	Log("Listen port = %d",sip_listen_port);
	server_addr.sin_port=NTOHS(sip_listen_port);
	if (bind(sipxmpp_sip_server_fd,(struct sockaddr *)&server_addr,server_addr_len)<0) 
	{
		Log("bind error........");
		return 1;
	}
	if(pthread_create(&sipxmpp_sip_reading_thread,NULL,sipxmpp_sip_reading,NULL))
	{
		Log("create thread error");
	}
	Log("sip server init finished.");
	return 0;
}

int destroy_sip_server()
{
	stopping = 1;
	struct sip_dialog *tmp_dialog;
	struct sip_header *tmp_sip_header;
	sip_package_t *tmp_sip_package;
	sip_dialog_t *tmp_sip_dialog;
	sip_nonce_t *tmp_sip_nonce;
	//first. we stop receive sip message.
	LogI("waitting sipxmpp_sip_reading_thread exit");
	if(sipxmpp_sip_reading_thread)
	{
		pthread_join(sipxmpp_sip_reading_thread,NULL);
		sipxmpp_sip_reading_thread = 0;
	}
	LogI("sipxmpp_sip_reading_thread exited.");

	//close udp socket.
	if(sipxmpp_sip_server_fd)
	{
		close(sipxmpp_sip_server_fd);
		sipxmpp_sip_server_fd = 0;
	}

	Log("cleaning up sip_dialogs");
	while(sip_dialogs)
	{
		tmp_sip_dialog = sip_dialogs->next;
		xmpp_release_sip_dialog(sip_dialogs);
		chkndfree(sip_dialogs);
		sip_dialogs = tmp_sip_dialog;
	}
	pthread_mutex_destroy(&sipxmpp_sip_dialogs_mutex);
	Log("clean up sipxmpp_request_commands success");


	//clean up headers
	Log("cleaning up allocated headers");
	pthread_mutex_lock(&sip_headers_mutex);
	while(sip_headers)
	{
		tmp_sip_header = sip_headers->nextinmemory;
		chkndfree(sip_headers);
		sip_headers = tmp_sip_header;
	}
	pthread_mutex_unlock(&sip_headers_mutex);
	pthread_mutex_destroy(&sip_headers_mutex);

	Log("cleaning up allocated nonces");
	pthread_mutex_lock(&sip_nonce_mutex);
	while(sip_nonces)
	{
		tmp_sip_nonce = sip_nonces->next;
		chkndfree(sip_nonces);
		sip_nonces = tmp_sip_nonce;
	}
	pthread_mutex_unlock(&sip_nonce_mutex);
	pthread_mutex_destroy(&sip_nonce_mutex);

	Log("cleaning up allocated packages");
	pthread_mutex_lock(&sip_packages_mutex);
	while(sip_packages)
	{
		tmp_sip_package = sip_packages->nextinmemory;
		chkndfree(sip_packages);
		sip_packages = tmp_sip_package;
	}
	pthread_mutex_unlock(&sip_packages_mutex);
	pthread_mutex_destroy(&sip_packages_mutex);

	chkndfree(sip_sendbuffer);
	chkndfree(sip_bodybuffer);
	return 0;
}
